package ca.etsmtl.logti.log619.lab05;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.internet.MimeMessage;

import ca.etsmtl.logti.log619.lab05.analyser.Analyser;
import ca.etsmtl.logti.log619.lab05.analyser.SpamAnalyser;
import ca.etsmtl.logti.log619.lab05.filter.EmailFilter;
import ca.etsmtl.logti.log619.lab05.utilities.BayesFilterBuilder;
import ca.etsmtl.utilities.ConsoleUtilities;

/**
 * Starting point of the Anti-SPAM application as defined for the LOG-619 course.
 * @author Maxime Caumartin <maxime.caumartin.1@ens.etsmtl.ca>
 */
public class Application
{
	public static final String applicationName = "619AntiSPAM";
	private static final String helpText = "This application will scan through all the email files given as a parameter" +
			"and determine if they are spam or not. The spam analysis is done by all the classes in the \\filter folder.\n";
	private static final int nbParams = 1;
	
	
	/**
	 * Starting point of the application.
	 * @param args Email files.
	 */
	public static void main(String[] args)
	{
		//Init Bayes database
		BayesFilterBuilder.buildDatabase();
		
		// Check arguments
		args = ConsoleUtilities.parseParameters(args); // Removes annoying parameters
		
		// Basic parameter validation
		if (args.length != nbParams)
		{
			// The order of the parameters here is important, since if args's length is 0, 
			// args[0] will throw a ArrayIndexOutOfBoundsException.
			if (args.length == 0 || ConsoleUtilities.isHelpDemand(args[0])) 
			{
				ConsoleUtilities.printUsage(applicationName,helpText,"Email List File");
				System.exit(0);
			}
			else
			{
				if ( args.length < nbParams)
					System.err.println("Error : Not enough parameters");
				else
					System.err.println("Error : Too many parameters");
				ConsoleUtilities.printUsage(applicationName,helpText,"Email List File");
				System.exit(1);
			}
		}
		
		// Presentation message
		System.out.println("Starting Analysis...");
		// Load EmailFilters
		
		ConsoleUtilities.debug("Scanning and loading EmailFilters...");
		EmailFilter[] filters = FilterFactory.getFilters();
		ConsoleUtilities.debugP(".",String.format("Loading EmailFilters complete. Number of classes loaded : %1$s",filters.length));
		
		// Create the output structure
		SpamAnalyser result = new Analyser();
		
		// Load email list
		try {
			BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(args[0])));
			String emailFilePath ;
			Session mimeSession = null;
			Pattern p = Pattern.compile("(.+)\\s++(.+)");
			
			// For each line in the file :
			while ((emailFilePath = r.readLine()) != null)
			{
				BufferedInputStream curEmail = null;
				
				// First group is the SPAM status for the email
				// Second group is the email file's path
				Matcher m = p.matcher(emailFilePath);
				m.matches(); // Triggers the pattern test.
				
				// Get current file
				File f = new File(m.group(2));
				if (!f.isFile()) // probably the saved file info is relative
					f = new File(args[0].substring(0, args[0].lastIndexOf("/")), m.group(2)); // Append the email list file's path to the actual email files 
				
				// Load the InputStream
				curEmail = new BufferedInputStream(new FileInputStream(f));

				// Validate email
				MimeMessage msg = new MimeMessage(mimeSession, curEmail);

				// Scan email
				for (EmailFilter filter : filters)
				{
					// Scan the email
					byte res = filter.checkSpam(msg);
					
					// Get the email's file
					String msgPath = m.group(2);
					
					// Get the name of the filter
					String filterName = filter.getFilterName();
					
					// Get the SPAM type
					SpamType spamType = SpamType.valueOf(m.group(1).trim());
					
					// Save the result
					result.addResult(msgPath,filterName,spamType, res );		
				}	
				// Rinse and repeat
				
				if (result.getTotalCount() % 5 == 0)
					ConsoleUtilities.debugP(".","Email checked : " + result.getTotalCount());
			}

		} catch (FileNotFoundException e) {
			System.err.println(String.format("Error : %1$s is not a file or is not found",args[0]));
			ConsoleUtilities.printUsage(applicationName,helpText,"Email List File");
			System.exit(2);
		} catch (IOException e) {
			System.err.println(String.format("Error : A problem occured reading a file.\nDetails : %1$s",e.getLocalizedMessage()));
			System.exit(3);
		} catch (MessagingException e) {
			System.err.println(String.format("Error : A problem occured parsing an email file.\nDetails : %1$s",e.getLocalizedMessage()));
			System.exit(4);
		}
		

		// Output result
		System.out.println("");
		System.out.println("Analysis complete");
		
		System.out.println(String.format("Number of email analyzed : %1$s",result.getTotalCount()));
		System.out.println(String.format("Number of SPAM detected : %1$s",result.getSPAMcount()));
		if (result.getFalseNegatives() != SpamAnalyser.NO_INFO || result.getFalsePositives() != SpamAnalyser.NO_INFO)
		{
			System.out.println(String.format("Number of false positives : %1$s",result.getFalsePositives()));
			System.out.println(String.format("Number of false negatives : %1$s",result.getFalseNegatives()));
		}
		System.out.println("Details :");
		System.out.println(result.analyserResult());
		
		// Exit normally
		System.exit(0);
	}
}